/*******************************************************************************
  * 文件：NetComm_FileDownload.c
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2020.04.29
  * 说明: 文件下载相关
*******************************************************************************/
#include "NetComm_FileDownload.h"
#include "NetComm_Cmd.h"
#include "NetComm_Comm.h"
#include "ComFun.h"
#include "Board.h"
#include "Debug.h"
#include "Led.h"
#include "Display.h"
#include "DevInfor.h"
#include <string.h>

#ifdef NETCOMM_FILEDOWNLOAD

static NetCommFileDownload_ts sNetCommFileDownload;
static FileDownloadShow_ts	sFileDownloadShow;
/*******************************************************************************
  * 函数名: NetCommOverTimeHook_
  * 功  能：通信超时回调处理函数
  * 参  数：无
  * 返回值：无
  * 说  明：文件下载过程中，若模块回复超时，则结束下载流程
*******************************************************************************/
static void NetCommOverTimeHook(U32 arg)
{
    // 文件下载失败
    NetCommFileDownloadStatusSet(eFILE_DOWNLOAD_FAIL);
    // 超时报告
    NetCommMsgHandleRet(eMSG_ERROR,(const S8*)STR_NETCOMM_MODULE_ACK_OVERTIME);
}
/*******************************************************************************
  * 函数名: NetCommMsgLogOptsStartHook_5S
  * 功  能：消息注册定时回调函数
  * 参  数：无
  * 返回值：无
  * 说  明：开启后不断发送消息注册报文，直到已注册，停止定时器
*******************************************************************************/
static void NetCommMsgLogOptsStartHook_5S(U32 arg)
{
    MsgStatus_te eMsgStatus = NetCommMsgStatusGet();
    
    if(eMSG_ALREADY_LOGON == eMsgStatus || eMSG_ALREADY_LOGOUT == eMsgStatus)
    {
        // 消息已注册（销），停止定时器
        Timer_Stop(&sNetCommFileDownload.sMsgStatusCheckTimer);
    }
    else
    {
        // 消息待注册（销），定时发送注册报文
        NetCommMsgLogOptsStart(eMsgStatus);
    }
}

/*******************************************************************************
  * 函数名: NetCommMsgLogOptsStart
  * 功  能：消息注册/销开始
  * 参  数：MsgStatus_te eMsgStatus：消息状态
  * 返回值：无
  * 说  明：开启后不断发送消息注册报文
*******************************************************************************/
void NetCommMsgLogOptsStart(MsgStatus_te eMsgStatus)
{
    U8* pu8Data = NULL;

    // 消息非待注测（销）操作
    if(eMSG_WAIT_LOGON != eMsgStatus && eMSG_WAIT_LOGOUT != eMsgStatus)
        return;
    
    // 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_12_DEV_UPWARD);
    // 消息注册子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_12_MSG_LOG & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_12_MSG_LOG & 0x00FF);

    if(eMSG_WAIT_LOGOUT == eMsgStatus)
    {
        // 消息注销模式
        *pu8Data++ = 0x00;
        *pu8Data++ = 0x00;
        // 类型数量
        *pu8Data++ = 0x00;
        *pu8Data++ = 0x00;
        // 发送数据包
        NetComm_SendPacket(pu8Data);
    }
    else if(eMSG_WAIT_LOGON == eMsgStatus)
    {
        // 消息注册模式
        *pu8Data++ = 0x00;
        *pu8Data++ = 0x01;
        // 类型数量（一个）
        *pu8Data++ = 0x00;
        *pu8Data++ = 0x01;
        // 类型值（0x0504为下载文件）
        *pu8Data++ = 0x05;
        *pu8Data++ = 0x04;
        // 发送数据包
        NetComm_SendPacket(pu8Data);
    }

    // 将消息状态更新待注册（销）
    sNetCommFileDownload.eMsgStatus = eMsgStatus;
    
    // 重启定时器
    Timer_Restart(&(sNetCommFileDownload.sMsgStatusCheckTimer), 
                u16SEC_TO_MSEC*5, 
                NetCommMsgLogOptsStartHook_5S,
                NULL, 
                FALSE);
}

/*******************************************************************************
  * 函数名: NetCommMsgLogOptsStartStop
  * 功  能：消息注册/销停止
  * 参  数：MsgStatus_te eMsgStatus：消息状态
  * 返回值：无
  * 说  明：开启后不断发送消息注册报文，直到已注册，停止定时器
*******************************************************************************/
void NetCommMsgLogOptsStartStop(void)
{
	Timer_Stop(&(sNetCommFileDownload.sMsgStatusCheckTimer));
}

/*******************************************************************************
  * 函数名: NetCommMsgStatusSet
  * 功  能：消息状态更新
  * 参  数：MsgStatus_te eMsgStatus:消息状态
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommMsgStatusSet(MsgStatus_te eMsgStatus)
{
	sNetCommFileDownload.eMsgStatus = eMsgStatus;
}

/*******************************************************************************
  * 函数名: NetCommMsgStatusGet
  * 功  能：消息状态获取
  * 参  数：无
  * 返回值：消息状态
  * 说  明：无
*******************************************************************************/
U8  NetCommMsgStatusGet(void)
{
    return (sNetCommFileDownload.eMsgStatus);
}

/*******************************************************************************
  * 函数名: NetCommMsgIDSet
  * 功  能：消息ID设置
  * 参  数：U8 MsgID[]:消息ID地址
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommMsgIDSet(U8 MsgID[])
{
    if(NULL == MsgID)
        return;
	
    DEBUG("Msg ID is:");
	DEBUG_ARR(MsgID,u8NETCOMM_FILEDOWNLOAD_MSGID_LEN);
    memcpy(sNetCommFileDownload.au8MsgID,MsgID,u8NETCOMM_FILEDOWNLOAD_MSGID_LEN);
}

/*******************************************************************************
  * 函数名: NetCommMsgIDGet
  * 功  能：获取消息ID
  * 参  数：无
  * 返回值：MsgID地址
  * 说  明：无
*******************************************************************************/
U8*  NetCommMsgIDGet(void)
{
    return (sNetCommFileDownload.au8MsgID);
}

/*******************************************************************************
  * 函数名: NetCommMsgLenSet
  * 功  能：消息长度设置
  * 参  数：U16 u16MsgLen：消息长度
  * 返回值：无
  * 说  明：在解析到新消息告知时，更新消息长度，并将接收的消息长度更新为0
*******************************************************************************/
void NetCommMsgLenSet(U16 u16MsgLen)
{
    //保存消息长度
    sNetCommFileDownload.u16MsgLen = u16MsgLen;
    //更新已接收消息长度
    sNetCommFileDownload.u16MsgRecvLen = 0;
}

/*******************************************************************************
  * 函数名: NetCommMsgLenGet
  * 功  能：获取消息长度
  * 参  数：无
  * 返回值：消息长度
  * 说  明：无
*******************************************************************************/
U16 NetCommMsgLenGet(void)
{
    return (sNetCommFileDownload.u16MsgLen);
}

/*******************************************************************************
  * 函数名: NetCommMsgHandle
  * 功  能：消息处理
  * 参  数：无
  * 返回值：无
  * 说  明：消息接收完成后调用，返回消息处理结果，并决定是否开始下载文件
*******************************************************************************/
static void NetCommMsgHandle(void)
{
    Bool bMsgInfor = TRUE; 
    Bool bFileInfor = TRUE;
    MsgInfor_ts*  psMsgInfor = (MsgInfor_ts*)(MSG_START_ADDR);
    FileInfor_ts* psFileInfor = (FileInfor_ts*)(psMsgInfor->au8FileInfor);

    // 消息格式判断
	if(psMsgInfor->au8ContentLen[0]!=0 || psMsgInfor->au8ContentLen[1]!=0)
	{
		DEBUG("Msg ContentLen: %d %d!\r\n",psMsgInfor->au8ContentLen[0],psMsgInfor->au8ContentLen[1]);
		bMsgInfor = FALSE;
	}
	
	if(psMsgInfor->au8Options[0]!=0 || psMsgInfor->au8Options[1]!=0)
	{
		DEBUG("Msg Options:%d %d!\r\n",psMsgInfor->au8Options[0],psMsgInfor->au8Options[1]);
		bMsgInfor = FALSE;
	}
	
    if(psMsgInfor->u8Style != 4 || psMsgInfor->u8Type !=5)
    {
		DEBUG("Msg Style:%d,Type:%d \r\n",psMsgInfor->u8Style,psMsgInfor->u8Type);
        bMsgInfor = FALSE;
    }
    
    if(bMsgInfor == FALSE)
    {
        // 消息格式解析失败
		DEBUG("Msg Format Error \r\n");
		// 回复错误
        NetCommMsgHandleRet(eMSG_ERROR,(const S8*)STR_NETCOMM_MSG_FORMAT_ERROR);
		// 文件下载失败
		NetCommFileDownloadStatusSet(eFILE_DOWNLOAD_FAIL);
        return;
    }
    
    // 文件格式判断
    if(psFileInfor->au8FileFormat[0] != 0x01 || psFileInfor->au8FileFormat[1] != 0x00)
    {
		DEBUG("FileFormat: %d %d!\r\n",psFileInfor->au8FileFormat[0],psFileInfor->au8FileFormat[1]);
        bFileInfor = FALSE;
    }

    if(psFileInfor->u8Alg != 1)
    {
		DEBUG("Alg: %dr\n",psFileInfor->u8Alg);
        bFileInfor = FALSE;
    }

    if(bFileInfor == FALSE)
    {
        // 文件格式解析失败
		DEBUG("File Format Error \r\n");
        NetCommMsgHandleRet(eMSG_ERROR,(const S8*)STR_NETCOMM_FILE_FORMAT_ERROR);
		// 文件下载失败
		NetCommFileDownloadStatusSet(eFILE_DOWNLOAD_FAIL);
        return;
    }
	
	// 保存要接受的文件大小
	sNetCommFileDownload.u32FileSize = Get_BigEndian_Value(psFileInfor->au8FileSize,4);
    // 保存消息、文件信息指针
    sNetCommFileDownload.psMsgInfor = psMsgInfor;
    sNetCommFileDownload.psFileInfor = psFileInfor;
    // 消息、文件格式正确，返回已读
	DEBUG("MSG Read\r\n");
    NetCommMsgHandleRet(eMSG_READ,(const S8*)STR_NETCOMM_NO_ERROR);
    // 发送文件下载请求
	DEBUG("Send File Download Ask\r\n");
    NetCommFileDownloadAsk();
}

/*******************************************************************************
  * 函数名: NetCommMsgPackAsk
  * 功  能：分包获取消息
  * 参  数：U16 u16MsgOffsetAdd：消息偏移地址
           U16 u16MsgOffsetLen：消息偏移长度
  * 返回值：无
  * 说  明：无
*******************************************************************************/
static void NetCommMsgPackAsk(U16 u16MsgOffsetAddr,U16 u16MsgOffsetLen)
{
    U8* pu8Data = NULL;

    DEBUG("Msg Pack Ask,OffsetAddr:%d,Len:%d\r\n",
                                 u16MsgOffsetAddr,
                                 u16MsgOffsetLen);
	
	// 备份偏移地址和长度，用于接收报文校验
    sNetCommFileDownload.u32OffsetAddrBak = u16MsgOffsetAddr;
	sNetCommFileDownload.u16LenBak = u16MsgOffsetLen;
	
	// 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_15_DEV_QUERY);
    // 获取消息子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_15_MSG_BODY_ASK & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_15_MSG_BODY_ASK & 0x00FF);
    // 消息ID
	memcpy(pu8Data,NetCommMsgIDGet(),u8NETCOMM_FILEDOWNLOAD_MSGID_LEN);
    pu8Data += u8NETCOMM_FILEDOWNLOAD_MSGID_LEN;
    // 消息偏移地址
    Put_BigEndian_Val(u16MsgOffsetAddr,pu8Data,2); 
    pu8Data += 2;
    // 消息偏移长度
    Put_BigEndian_Val(u16MsgOffsetLen,pu8Data,2); 
    pu8Data += 2;
    // 发送数据包
    NetComm_SendPacket(pu8Data);
	
	// 开启超时检测软件定时器，1min
	sNetCommFileDownload.u8OverTimeTick = 0;
	Timer_Restart(&(sNetCommFileDownload.sCommOverTimeCheckTimer),
	               u16MIN_TO_MSEC,
	               NetCommOverTimeHook,
	               NULL,
	               FALSE);
}

/*******************************************************************************
  * 函数名: NetCommMsgAsk
  * 功  能：开始获取消息体
  * 参  数：无
  * 返回值：无
  * 说  明：收到消息告知后，调用此函数，开始查询消息体
*******************************************************************************/
void NetCommMsgAsk(void)
{
    U16 u16MsgLen = sNetCommFileDownload.u16MsgLen;//消息总长度
    U16 u16MsgRecvLen = sNetCommFileDownload.u16MsgRecvLen;//已接收的消息长度，作为偏移地址
    
    if((u16MsgLen - u16MsgRecvLen) >= u8NETCOMM_FILEDOWNLOAD_PACK_LEN)
    {
        // 待查询的消息数据超过128字节，按照每包128字节查询
        NetCommMsgPackAsk(u16MsgRecvLen,u8NETCOMM_FILEDOWNLOAD_PACK_LEN);
		// 消息尚未收完
		sNetCommFileDownload.bMsgRecvDoneFlag = FALSE;
    }
    else if((u16MsgLen - u16MsgRecvLen) > 0)
    {
        // 待查询的消息数据大于零且未超过128字节，查询剩余全部数据
        NetCommMsgPackAsk(u16MsgRecvLen,(u16MsgLen - u16MsgRecvLen));
		// 消息尚未收完
		sNetCommFileDownload.bMsgRecvDoneFlag = FALSE;
    }
    else if((u16MsgLen - u16MsgRecvLen) == 0)
    {
		// 待查询的消息数据已查完
        DEBUG("Msg Pack Ask Done\r\n");
		
		if(sNetCommFileDownload.bMsgRecvDoneFlag == FALSE)
		{
			// 更新标志位为TRUE
			sNetCommFileDownload.bMsgRecvDoneFlag = TRUE;
			// 消息数据已查完，返回已收
			NetCommMsgHandleRet(eMSG_RECV,(const S8*)STR_NETCOMM_NO_ERROR);
			// 消息处理
			NetCommMsgHandle();			
		}
    }
}

/*******************************************************************************
  * 函数名: NetCommMsgSave
  * 功  能：消息保存
  * 参  数：U16 u16MsgOffsetAddr：消息偏移地址
           U8* pu8MsgData：消息数据
           U8 pu8MsgDataLen：数据长度
  * 返回值：无
  * 说  明：收到消息告知后，调用此函数，开始查询消息体
*******************************************************************************/
void NetCommMsgSave(U16 u16MsgOffsetAddr,U8* pu8MsgData,U8 u8MsgDataLen)
{
    Bool bFlashWrite = UNDONE; 
    
    // 偏移地址不合法
    if(u16MsgOffsetAddr > MSG_SIZE)
      return;

	// 该包消息已经保存过
	if(0 == memcmp(pu8MsgData,(U8*)(MSG_START_ADDR+u16MsgOffsetAddr),u8MsgDataLen))
		return ;
	
    DEBUG("Msg Save OffsetAddr:%d,ActualAddr:%d,Len:%d\r\n",
                             u16MsgOffsetAddr,
							 MSG_START_ADDR+u16MsgOffsetAddr,
                             u8MsgDataLen);
	DEBUG("Msg Pack Data:");
	DEBUG_ARR(pu8MsgData,u8MsgDataLen);
	
    if(u8MsgDataLen&0x03)
    {
        // 最后一包消息不是四字节整数倍，补足四字节整数倍
        U8 u8MsgDataLen1 = u8MsgDataLen+4-(u8MsgDataLen&0x03);
		DEBUG("Flash Save Last Pack!\r\n");
        bFlashWrite = ESP508Flash_Write(pu8MsgData,
                                        (U32)(MSG_START_ADDR+u16MsgOffsetAddr),
                                        (U32)(u8MsgDataLen1/4));
    }
    else
    {
		DEBUG("Flash Save Pack\r\n");
        bFlashWrite = ESP508Flash_Write(pu8MsgData,
                                        (U32)(MSG_START_ADDR+u16MsgOffsetAddr),
                                        (U32)(u8MsgDataLen/4)); 
    }
    
    if(bFlashWrite)
    {
        //flash写成功，更新已接收消息长度
		sNetCommFileDownload.u16MsgRecvLen += u8MsgDataLen;
		DEBUG("Flash Write Msg Pack Success,MsgRecvLen:%d\r\n",sNetCommFileDownload.u16MsgRecvLen);
    }
}

/*******************************************************************************
  * 函数名: NetCommMsgErase
  * 功  能：消息擦除
  * 参  数：无
  * 返回值：无
  * 说  明：收到新消息告知后，调用此函数，擦除Flash
*******************************************************************************/
void NetCommMsgErase(void)
{
    DEBUG("Msg Erase!\r\n");
    ESP508Flash_Erase(MSG_START_ADDR,MSG_SIZE/1024);
}

/*******************************************************************************
  * 函数名: NetCommMsgHandleRet
  * 功  能：消息处理结果返回
  * 参  数：MsgHandleRet_te eResult：消息处理结果
           const S8* psErrNo:消息处理错误码（字符串）
  * 返回值：无
  * 说  明：当返回消息解析错误时，结束整个流程
*******************************************************************************/
void NetCommMsgHandleRet(MsgHandleRet_te eResult,const S8* psErrNo)
{
    U8* pu8Data = NULL;
    
    // 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_12_DEV_UPWARD);
    
    // 获取消息子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_12_MSG_HANDLE_RESULT & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_12_MSG_HANDLE_RESULT & 0x00FF);
    // 消息ID
	memcpy(pu8Data,NetCommMsgIDGet(),u8NETCOMM_FILEDOWNLOAD_MSGID_LEN);
    pu8Data += u8NETCOMM_FILEDOWNLOAD_MSGID_LEN;
    // 消息处理状态
    *pu8Data++ = 0x00;
    *pu8Data++ = (U8)eResult;
    // 消息处理错误码
    memcpy(pu8Data,psErrNo,6);
    pu8Data += 6;
    // 消息处理详细信息长度（默认为0）
    *pu8Data++ = 0x00;
    // 发送数据包
    NetComm_SendPacket(pu8Data);
}

/*******************************************************************************
  * 函数名: NetCommFileDownloadStatusSet
  * 功  能：文件下载状态设置
  * 参  数：FileStatus_te eFileStatus：文件下载状态
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileDownloadStatusSet(FileStatus_te eFileStatus)
{
    sNetCommFileDownload.eFileStatus = eFileStatus;
}

/*******************************************************************************
  * 函数名: NetCommFileDownloadStatusGet
  * 功  能：文件下载状态获取
  * 参  数：无
  * 返回值：FileStatus_te eFileStatus：文件下载状态
  * 说  明：无
*******************************************************************************/
S8 NetCommFileDownloadStatusGet(void)
{
	return sNetCommFileDownload.eFileStatus;
}
/*******************************************************************************
  * 函数名: NetCommFileErase
  * 功  能：擦除Flash文件区
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileErase(void)
{
	DEBUG("File Flash Erase\r\n");
    ESP508Flash_Erase(FILE_START_ADDR,FILE_SIZE/1024);
}

/*******************************************************************************
  * 函数名: NetCommFileDownloadAsk
  * 功  能：文件下载请求
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileDownloadAsk(void)
{
    U8* pu8Data = NULL;
    
    // 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_12_DEV_UPWARD);
    
    // 获取消息子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_12_FILE_DOWNLOAD_ASK & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_12_FILE_DOWNLOAD_ASK & 0x00FF);
    // 文件标识（只下载1个文件）
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x01;
    // 文件信息数量
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x06;
    //文件大小
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x01;
    //文件URL长度
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x02;
    //文件URL
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x03;
    //文件校验算法
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x04;
    //文件校验信息
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x05;
    //文件大小
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x06;

    // 发送数据包
    NetComm_SendPacket(pu8Data);
}

/*******************************************************************************
  * 函数名: NetCommFileInforAck
  * 功  能：文件信息应答
  * 参  数：U16 u16FileInforID：文件信息ID
           U16 u16OffsetAddr：文件信息偏移地址
           U16 U16Len：文件信息偏移长度
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileInforAck(U16 u16FileInforID,U16 u16OffsetAddr,U16 U16Len)
{
    U8* pu8Data = NULL;

    // 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_14_MODILE_QUERY_ACK);

    // 文件信息应答子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_14_FILE_INFOR_REPLY & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_14_FILE_INFOR_REPLY & 0x00FF);
    // 文件标识（只对一号文件）
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x01;
    // 文件信息标识
    *pu8Data++ = (U8)((u16FileInforID & 0xFF00)>>8);
    *pu8Data++ = (U8)(u16FileInforID & 0x00FF);

    // 根据文件信息标识，查找文件信息数据
    switch (u16FileInforID)
    {
        // 文件大小
        case U16_NETCOMM_FILEINFOR_SIZE:  
        {
            memcpy(pu8Data,sNetCommFileDownload.psFileInfor->au8FileSize,4);
            pu8Data += 4;
			DEBUG("File Size:%d\r\n",(int)Get_BigEndian_Value(sNetCommFileDownload.psFileInfor->au8FileSize,4));
        }
        break;
        // URL长度
        case U16_NETCOMM_FILEINFOR_URL_LEN:
        {
            memcpy(pu8Data,sNetCommFileDownload.psFileInfor->au8UrlLen,2);
            pu8Data += 2;
			DEBUG("URL Len:%d\r\n",(int)Get_BigEndian_Value(sNetCommFileDownload.psFileInfor->au8UrlLen,2));
        }
        break;
        // 文件URL
        case U16_NETCOMM_FILEINFOR_URL:
        {
            // URL偏移地址
            Put_BigEndian_Val(u16OffsetAddr,pu8Data,2); 
            pu8Data +=2;
            // 偏移长度
            Put_BigEndian_Val(U16Len,pu8Data,2); 
            pu8Data +=2;
            // URL偏移内容
            memcpy(pu8Data,
                   sNetCommFileDownload.psFileInfor->au8Url+u16OffsetAddr,
                   U16Len);
            pu8Data += U16Len;
        }
        break;
        // 文件校验算法
        case U16_NETCOMM_FILEINFOR_ALG:
        {
            *pu8Data++ = sNetCommFileDownload.psFileInfor->u8Alg;
			DEBUG("ALG:%d\r\n",sNetCommFileDownload.psFileInfor->u8Alg);
        }
        break;
        // 文件校验信息
        case U16_NETCOMM_FILEINFOR_HASH:
        {
            memcpy(pu8Data,sNetCommFileDownload.psFileInfor->au8Hash,32);
            pu8Data += 32;
			DEBUG("Hash:");
			DEBUG_ARR(sNetCommFileDownload.psFileInfor->au8Hash,32);
        }
        break;
        case U16_NETCOMM_FILEINFOR_TOKEN:
        {
            memcpy(pu8Data,sNetCommFileDownload.psFileInfor->au8Token,32);
            pu8Data += 32;
			DEBUG("Token:");
			DEBUG_ARR(sNetCommFileDownload.psFileInfor->au8Token,32);
        }
        break;
        default :
        return;
    }

    // 发送数据包
    NetComm_SendPacket(pu8Data);
}

/*******************************************************************************
  * 函数名: NetCommFileHandleRet
  * 功  能：文件处理结果返回
  * 参  数：U16 u16FileID：文件标识
            const S8* psErrNo：结果码，字符串
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileHandleRet(U16 u16FileID,const S8* psErrNo)
{
    U8* pu8Data = NULL;
    
    // 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_12_DEV_UPWARD);
    
    // 文件传输处理子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_12_FILE_TRANSPORT_RESULT & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_12_FILE_TRANSPORT_RESULT & 0x00FF);
    // 文件标识
    *pu8Data++ = (U8)((u16FileID & 0xFF00)>>8);
    *pu8Data++ = (U8)(u16FileID & 0x00FF);
    // 文件传输处理错误码
    memcpy(pu8Data,psErrNo,6);
    pu8Data += 6;
    // 发送数据包
    NetComm_SendPacket(pu8Data);
}

/*******************************************************************************
  * 函数名: NetCommFilePackAsk
  * 功  能：文件数据包请求
  * 参  数：U16 u16OffsetAddr:偏移地址（相对于整个文件）
            U16 u16Len：数据长度
  * 返回值：无
  * 说  明：无
*******************************************************************************/
static void NetCommFilePackAsk(U32 u32OffsetAddr,U16 u16Len)
{
    U8* pu8Data = NULL;
    
	// 备份偏移地址和长度，用于接收报文校验
    sNetCommFileDownload.u32OffsetAddrBak = u32OffsetAddr;
	sNetCommFileDownload.u16LenBak = u16Len;
	
    // 构建发送数据包
    pu8Data = NetComm_SetupSendPacket(U8_NETCOMM_CMD_15_DEV_QUERY);
    
    // 获取文件子命令
    *pu8Data++ = (U8)((U16_NETCOMM_CMD_15_FILE_BODY_ASK & 0xFF00)>>8);
    *pu8Data++ = (U8)(U16_NETCOMM_CMD_15_FILE_BODY_ASK & 0x00FF);
    // 文件标识（只对一个文件）
    *pu8Data++ = 0x00;
    *pu8Data++ = 0x01;
    // 消息偏移地址
    Put_BigEndian_Val(u32OffsetAddr,pu8Data,4); 
    pu8Data += 4;
    // 消息偏移长度
    Put_BigEndian_Val(u16Len,pu8Data,2); 
    pu8Data += 2;
    // 发送数据包
    NetComm_SendPacket(pu8Data);

    // 开启超时检测软件定时器
    sNetCommFileDownload.u8OverTimeTick = 0;
	Timer_Restart(&(sNetCommFileDownload.sCommOverTimeCheckTimer),
	               u16MIN_TO_MSEC,
	               NetCommOverTimeHook,
	               NULL,
	               FALSE);
}

/*******************************************************************************
  * 函数名: NetCommFileAsk
  * 功  能：文件数据请求
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileAsk(void)
{
    // 当前轮次数据总大小
    U32 u32CurRoundSize = sNetCommFileDownload.u32CurRoundSize;
    // 当前轮次已接收数据大小，作为偏移地址
    U32 u32CurRoundRecvSize = sNetCommFileDownload.u32CurRoundRecvSize;
    // 当前轮次起始偏移地址，作为基地址
    U32 u32CurRoundOffsetAddr = sNetCommFileDownload.u32CurRoundOffsetAddr;

    DEBUG("File Pack Ask,OffsetAddr:%d\r\n",u32CurRoundOffsetAddr + u32CurRoundRecvSize);

    if((u32CurRoundSize - u32CurRoundRecvSize) >= u8NETCOMM_FILEDOWNLOAD_PACK_LEN)
    {
        // 本轮剩余文件大小超过128B
        NetCommFilePackAsk(u32CurRoundOffsetAddr + u32CurRoundRecvSize,
                           u8NETCOMM_FILEDOWNLOAD_PACK_LEN);
    }
    else if((u32CurRoundSize - u32CurRoundRecvSize) > 0)
    {
        // 本轮剩余文件大小未超过128B
        NetCommFilePackAsk(u32CurRoundOffsetAddr + u32CurRoundRecvSize,
                           (u32CurRoundSize - u32CurRoundRecvSize));
    }
    else if((u32CurRoundSize - u32CurRoundRecvSize) == 0)
    {
		// 本轮剩余文件大小为0
        DEBUG("CurRound File Ask Done!\r\n");
       
		// 本轮文件已查完，发送文件处理结果
		if(sNetCommFileDownload.bCurRoundRecvDoneFlag == FALSE)
		{
		    // 防止重复发送文件处理结果
			sNetCommFileDownload.bCurRoundRecvDoneFlag = TRUE;
			NetCommFileHandleRet(0x0001,(const S8*) STR_NETCOMM_NO_ERROR);
		}

        if(sNetCommFileDownload.u16CurRound == sNetCommFileDownload.u16RoundNums)
        {
			// 当前轮次为最后一轮
            DEBUG("All File Ask Done!\r\n");
            // 文件传输已完成，更新文件传输状态
            NetCommFileDownloadStatusSet(eFILE_DOWNLOAD_SUCCESS);
            // 发送消息处理结果
            NetCommMsgHandleRet(eMSG_DONE,(const S8*)STR_NETCOMM_NO_ERROR);
			// 将文件大小保存至flash参数区
			Dev_SetMenuSize(sNetCommFileDownload.u32FileSize);
			// 更新文件下载标志
			Dev_SetMenuSave(TRUE);
        }
    }
}

/*******************************************************************************
  * 函数名: NetCommFileSave
  * 功  能：文件保存
  * 参  数：U32 u32OffsetAddr：数据偏移地址（相对于整个文件）
			U8* pu8FileData：数据起始地址
			U16 u16Len：数据长度
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileSave(U32 u32OffsetAddr,U8* pu8FileData,U16 u16Len)
{
    // Flash写入完成标志位
    Bool bFlashWrite = TRUE; 
        
    // 数据长度不合法
    if(u16Len > sNetCommFileDownload.u32CurRoundSize)
      return;
      
	// 该包数据已经保存过
	if(0 == memcmp(pu8FileData,(U8*)(FILE_START_ADDR+u32OffsetAddr),u16Len))
		return;
	
    DEBUG("File Save,OffsetAddr:%d,Len:%d\r\n",
                                 (int)u32OffsetAddr,
                                 u16Len);  
    if(u16Len&0x03)
    {
        // 最后一包消息不是四字节整数倍，补足四字节整数倍
        U8 u8DataLen1 = u16Len+4-(u16Len&0x03);
        bFlashWrite = ESP508Flash_Write(pu8FileData,
                                        FILE_START_ADDR+u32OffsetAddr,
                                        u8DataLen1/4);
    }
    else
    {
        bFlashWrite = ESP508Flash_Write(pu8FileData,
                                        FILE_START_ADDR+u32OffsetAddr,
                                        u16Len/4); 
    }
    
    if(bFlashWrite)
    {
        //flash写成功，更新已接收消息长度，后文会根据此长度，查询下一包数据
        sNetCommFileDownload.u32CurRoundRecvSize += u16Len;
    }
}

/*******************************************************************************
  * 函数名: NetCommFileTransRoundSet
  * 功  能：文件下载轮数信息设置
  * 参  数：U16 u16RoundNums：总轮数
           U16 u16CurRound：当前轮数
           U32 u32Size：当前轮次数据长度
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileTransRoundSet(U16 u16RoundNums,U16 u16CurRound,U32 u32OffsetAddr,U32 u32Size)
{
    sNetCommFileDownload.u16RoundNums 			= u16RoundNums;
    sNetCommFileDownload.u16CurRound  			= u16CurRound;
    sNetCommFileDownload.u32CurRoundOffsetAddr 	= u32OffsetAddr;
    sNetCommFileDownload.u32CurRoundSize 		= u32Size;
    sNetCommFileDownload.u32CurRoundRecvSize 	= 0;
	sNetCommFileDownload.bCurRoundRecvDoneFlag 	= FALSE;
}

/*******************************************************************************
  * 函数名: NetCommOverTimeRest
  * 功  能：通讯超时检测停止
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommOverTimeCheckStop(void)
{
    sNetCommFileDownload.u8OverTimeTick = 0;
    Timer_Stop(&sNetCommFileDownload.sCommOverTimeCheckTimer);
}

/*******************************************************************************
  * 函数名: NetCommOffsetAddrGet
  * 功  能：获取偏移地址
  * 参  数：无
  * 返回值：发送查包报文时的偏移地址
  * 说  明：接收文件数据包或消息数据包的时候调用，用于校验接收的数据偏移地址是否正确
*******************************************************************************/
U32 NetCommOffsetAddrGet(void)
{
	return sNetCommFileDownload.u32OffsetAddrBak;
}

/*******************************************************************************
  * 函数名: NetCommLenGet
  * 功  能：获取数据长度
  * 参  数：无
  * 返回值：发送查包报文时的数据长度
  * 说  明：接收文件数据包或消息数据包的时候调用，用于校验接收的数据长度是否正确
*******************************************************************************/
U16 NetCommLenGet(void)
{
	return sNetCommFileDownload.u16LenBak;
}

/*******************************************************************************
  * 函数名: NetCommFileSizeGet
  * 功  能：获取文件长度
  * 参  数：无
  * 返回值：U32：已下载的文件大小
  * 说  明：返回已下载的文件大小
*******************************************************************************/
U32 NetCommFileSizeGet(void)
{
	return sNetCommFileDownload.u32FileSize;
}

/*******************************************************************************
  * 函数名: NetCommFileDownloadShowHook_1S
  * 功  能：文件下载进度显示
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileDownloadShowHook_1S(U32 arg)
{
	// 检测菜谱下载状态
	if(eFILE_DOWNLOAD_IN_PROGRESS == NetCommFileDownloadStatusGet())
	{
		// 菜谱下载中
		sFileDownloadShow.u16StartTick++;
		sFileDownloadShow.u8EndTick = 0;
		sFileDownloadShow.u8ErrTick = 0;
		
		// 关闭数码管
		Display_AllOff();
		
		// 智能LED闪烁
		if(sFileDownloadShow.u16StartTick%2)
		{
			Led_Control(eLED_SIMPLE,eLED_NO_BRIGHT);	
			DEBUG("eLED_SIMPLE eLED_NO_BRIGHT\r\n");
		}
		else
		{
			Led_Control(eLED_SIMPLE,eLED_HALF_BRIGHT);
			DEBUG("eLED_SIMPLE eLED_HALF_BRIGHT\r\n");
		}
		
		if(sFileDownloadShow.u16StartTick >= 600)
		{
			Timer_Stop(&sFileDownloadShow.sTimer);
		}
	}
	else if(eFILE_DOWNLOAD_SUCCESS == NetCommFileDownloadStatusGet())
	{
		// 菜谱下载成功
		sFileDownloadShow.u8EndTick++;
		sFileDownloadShow.u16StartTick = 0;
		sFileDownloadShow.u8ErrTick   = 0;
		
		if(sFileDownloadShow.u8EndTick <= 3)
		{
			// 显示CCC
			Display_Show(eDISPLAY_MENU,0);
		}
		else
		{
			// 关闭数码管
			Display_AllOff();
			Timer_Stop(&sFileDownloadShow.sTimer);
		}
	}
	else if(eFILE_DOWNLOAD_FAIL == NetCommFileDownloadStatusGet())
	{
		// 菜谱下载失败
		sFileDownloadShow.u8ErrTick++;
		sFileDownloadShow.u8EndTick = 0;
		sFileDownloadShow.u16StartTick = 0;
		
		if(sFileDownloadShow.u8ErrTick <= 10)
		{
			// 显示Err
			Display_Show(eDISPLAY_ERR,0);
		}
		else
		{
			// 关闭数码管
			Display_AllOff();
			Timer_Stop(&sFileDownloadShow.sTimer);
		}
	}
}

/*******************************************************************************
  * 函数名: NetCommFileDownloadShowStart
  * 功  能：文件下载进度显示
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileDownloadShowStart(void)
{
	/****文件下载过程显示****/
	sFileDownloadShow.u16StartTick = 0;
	sFileDownloadShow.u8EndTick    = 0;
	sFileDownloadShow.u8ErrTick    = 0;
	Timer_Restart(&sFileDownloadShow.sTimer,
				u16SEC_TO_MSEC,
				NetCommFileDownloadShowHook_1S,
				NULL,
				TRUE);
}

/*******************************************************************************
  * 函数名: NetCommFileDownload_Init
  * 功  能：文件下载初始化
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void NetCommFileDownload_Init(void)
{
    // 上电消息默认初始化状态，即未注册
    sNetCommFileDownload.eMsgStatus     = eMSG_INIT;
    sNetCommFileDownload.u16MsgLen      = 0;
    sNetCommFileDownload.u16MsgRecvLen  = 0;
	 
	sNetCommFileDownload.eFileStatus    = eFILE_DOWNLOAD_NOT_START;
    sNetCommFileDownload.u32FileSize    = 0;
    sNetCommFileDownload.u32FileRecvSize= 0;
    sNetCommFileDownload.u16RoundNums   = 0;
    sNetCommFileDownload.u16CurRound    = 0;
    sNetCommFileDownload.u32CurRoundOffsetAddr = 0;
    sNetCommFileDownload.u32CurRoundSize       = 0;
    sNetCommFileDownload.u32CurRoundRecvSize   = 0;
    sNetCommFileDownload.u8OverTimeTick = 0;
	sNetCommFileDownload.u32OffsetAddrBak = 0;
	sNetCommFileDownload.u16LenBak = 0;
	sNetCommFileDownload.bCurRoundRecvDoneFlag = FALSE;
	sNetCommFileDownload.bMsgRecvDoneFlag = FALSE;
}

#endif

